﻿using Autofac;
using Autofac.Extensions.DependencyInjection;
using FastMvc.Crud;
using FastMvc.MiddleWare;
using FastMvc.Repositories;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;

namespace FastMvc
{
    /// <summary>
    /// 基本启动类，提供启动服务的各种注册
    /// </summary>
    public class BaseStartUp
    {
        public IConfiguration Configuration { get; }

        public BaseStartUp(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public virtual IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("any", builder =>
                {
                    builder.SetIsOriginAllowed(o => true)
                           .AllowAnyMethod()
                           .AllowAnyHeader()
                           .AllowCredentials();
                });
            });

            // 接口J送格式去除首字母小写
            services.AddControllers()
                .AddJsonOptions(option => option.JsonSerializerOptions.PropertyNamingPolicy = null)
                .ConfigureApiBehaviorOptions(options =>
                {
                    options.SuppressModelStateInvalidFilter = true;  //抑制系统自带模型验证
                });

            //返回Json格式化的统一
            services.AddControllersWithViews().AddNewtonsoftJson(option =>
            {
                option.SerializerSettings.ContractResolver = new DefaultContractResolver();
                option.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                option.SerializerSettings.Converters.Add(new StringEnumConverter());
            });

            //注册Swagger页面
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = $"{SwaggerName} Documents", Version = "v1" });
                // API注释的xml文档
                var Dir = new DirectoryInfo(System.Environment.CurrentDirectory);
                foreach (var file in Dir.GetFiles("*.xml"))
                {
                    options.IncludeXmlComments(file.FullName, true);
                }

                options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
                {
                    Description = "JWT Authorization header using the scheme. Example: \"Authorization: {token}\"",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey
                });

                options.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "TokenAuth"
                            }
                        },
                        new string[] {}
                    }
                });
            });

            services.AddMvc(option =>
            {
                option.Filters.Add(new Filters.DtoValidationFilter());   // Dto格式验证
                option.Filters.Add(new Filters.UserSetActionFilter());   // 设置UserAuth信息
                option.Filters.Add(new Filters.PermissionCheckFilter()); // Permission检查
            });

            // 依赖注入，使用Autofac
            var builder = new ContainerBuilder();//实例化 AutoFac  容器   
            ConfigContainerBuilder(builder);
            builder.Populate(services);
            var ApplicationContainer = builder.Build();
            return new AutofacServiceProvider(ApplicationContainer);//第三方IOC接管 core内置DI容器
        }
        public virtual string SwaggerName => "Swagger";

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // 注册统一的错误处理 (最先注册，放在最外层)
            app.UseFMExceptionHandler();
            // 注册统一的权限检查
            app.UseAuthHandler();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseDefaultFiles();
            app.UseStaticFiles();

            // 开启Swagger
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", SwaggerName);
                c.RoutePrefix = "docs";
            });

            app.UseRouting();
            app.UseCors("any");
        }

        public virtual void ConfigContainerBuilder(ContainerBuilder builder)
        {
            var dir = new DirectoryInfo(System.Environment.CurrentDirectory);
            // Service类的注册
            var tFiles = dir.GetFiles("*.Service.dll");
            foreach (var tFile in tFiles)
            {
                var tAss = Assembly.LoadFrom(tFile.Name);
                builder.RegisterAssemblyTypes(tAss)
                    .Where(t => !t.IsAbstract && t.Name.EndsWith("Service"))
                    .AsImplementedInterfaces()
                    .PropertiesAutowired()
                    .OnActivated(r =>
                    {
                        Console.WriteLine(r.ToString());
                    });
            }

            // 其他类库中的一些共用类的注册
            // TO_DO 解析自动注册，怎么搞？
            // 仓储
            //builder.RegisterGeneric(typeof(FastMVCRepository<,,>)).As(typeof(IRepository<,,>));
            builder.RegisterGeneric(typeof(SqlSugarRepository<,>)).As(typeof(IRepository<,>));
            builder.RegisterGeneric(typeof(SqlSugarMVCRepository<>)).As(typeof(IRepository<>));

            // CrudService
            builder.RegisterGeneric(typeof(CrudService<,,,,,>));
            builder.RegisterGeneric(typeof(CrudService<,,,>));
            builder.RegisterGeneric(typeof(CrudService<,,,>));
            builder.RegisterGeneric(typeof(CrudService<,,>));
            builder.RegisterGeneric(typeof(CrudService<,>));
            //builder.RegisterGeneric(typeof(CrudService<,,,,,>)).As(typeof(ICrudService<,,,,,>));
            //builder.RegisterGeneric(typeof(CrudService<,,,>)).As(typeof(ICrudService<,,,>));
            //builder.RegisterGeneric(typeof(CrudService<,,,>)).As(typeof(ICrudService<,,,>));
            //builder.RegisterGeneric(typeof(CrudService<,,>)).As(typeof(ICrudService<,,>));
            //builder.RegisterGeneric(typeof(CrudService<,>)).As(typeof(ICrudService<,>));
        }
    }
}
